package models

import (
	"errors"
	"fmt"
	"reflect"
	"strings"
	"time"

	// "strconv"
	"gitee.com/lzqysoft/ims/libs/cache"
	"github.com/astaxie/beego"
	"github.com/astaxie/beego/orm"

	// "ims/libs/encrypt"
	"gitee.com/lzqysoft/ims/libs/params"
)

// Dept Dept
type Dept struct {
	Id           string         `orm:"column(id);pk"`
	Organization *Organization  `orm:"rel(fk)"`
	Name         string         `orm:"column(name)"`
	Remark       string         `orm:"column(remark);null"`
	Pid          string         `orm:"column(pid)"`
	Level        int            `orm:"column(level)"`
	Seq          int            `orm:"column(seq)"`
	Status       int            `orm:"column(status)"`
	Isdelete     int            `orm:"column(isdelete)"`
	Ctime        time.Time      `orm:"column(ctime);type(timestamp with time zone)"`
	Creater      string         `orm:"column(creater)"`
	Utime        time.Time      `orm:"column(utime);type(timestamp with time zone)"`
	Updater      string         `orm:"column(updater)"`
	Director     string         `orm:"column(director)"`
	DeptCode     string         `orm:"column(dept_code)"`
	ParentCode   string         `orm:"column(parent_code)"`
	User         []*User        `orm:"reverse(many)"`
	Livechannel  []*Livechannel `orm:"reverse(many)"`
	Video        []*Video       `orm:"reverse(many)"`
}

// TableName TableName
func (t *Dept) TableName() string {
	return "sys_dept"
}

func init() {
	orm.RegisterModel(new(Dept))
}

// AddDept insert a new Dept into database and returns
// last inserted Id on success.
func AddDept(m *Dept) (id int64, err error) {
	o := orm.NewOrm()
	id, err = o.Insert(m)
	return
}

// GetDeptById retrieves Dept by Id. Returns error if
// Id doesn't exist
func GetDeptById(id string) (v *Dept, err error) {
	o := orm.NewOrm()
	v = &Dept{Id: id}
	if err = o.Read(v); err == nil {
		o.LoadRelated(v, "Organization")
		o.LoadRelated(v, "User")
		return v, nil
	}
	return nil, err
}

// GetAllDept retrieves all Dept matches certain condition. Returns empty list if
// no records exist
func GetAllDept(query map[string]string, fields []string, sortby []string, order []string,
	offset int64, limit int64) (ml []interface{}, err error) {
	o := orm.NewOrm()
	qs := o.QueryTable(new(Dept))
	// query k=v
	for k, v := range query {
		// rewrite dot-notation to Object__Attribute
		k = strings.Replace(k, ".", "__", -1)
		qs = qs.Filter(k, v)
	}
	qs = qs.Filter("Isdelete", 0)
	//cond := orm.NewCondition()
	//cond1 := cond.AndNot("Pid", "0")
	//qs = qs.SetCond(cond1)
	// order by:
	var sortFields []string
	if len(sortby) != 0 {
		if len(sortby) == len(order) {
			// 1) for each sort field, there is an associated order
			for i, v := range sortby {
				orderby := ""
				if order[i] == "desc" {
					orderby = "-" + v
				} else if order[i] == "asc" {
					orderby = v
				} else {
					return nil, errors.New("Error: Invalid order. Must be either [asc|desc]")
				}
				sortFields = append(sortFields, orderby)
			}
			qs = qs.OrderBy(sortFields...)
		} else if len(sortby) != len(order) && len(order) == 1 {
			// 2) there is exactly one order, all the sorted fields will be sorted by this order
			for _, v := range sortby {
				orderby := ""
				if order[0] == "desc" {
					orderby = "-" + v
				} else if order[0] == "asc" {
					orderby = v
				} else {
					return nil, errors.New("Error: Invalid order. Must be either [asc|desc]")
				}
				sortFields = append(sortFields, orderby)
			}
		} else if len(sortby) != len(order) && len(order) != 1 {
			return nil, errors.New("Error: 'sortby', 'order' sizes mismatch or 'order' size is not 1")
		}
	} else {
		if len(order) != 0 {
			return nil, errors.New("Error: unused 'order' fields")
		}
	}

	var l []orm.Params
	qs = qs.RelatedSel().OrderBy(sortFields...)
	if _, err = qs.Limit(limit, offset).Values(&l, fields...); err == nil {
		if len(fields) == 0 {
			for _, v := range l {
				u, _ := GetDeptById(v["Id"].(string))
				r, err := GetDeptById(v["Pid"].(string))
				if err == nil && len(r.Name) > 0 {
					v["Pname"] = r.Name
				} else {
					v["Pname"] = "顶级部门"
				}
				v["OrgId"] = u.Organization.Id
				v["OrgName"] = u.Organization.Name
				v["Sname"] = params.GetStatus(u.Status)
				ml = append(ml, v)
			}
		} else {
			// trim unused fields
			for _, v := range l {
				m := make(map[string]interface{})
				val := reflect.ValueOf(v)
				for _, fname := range fields {
					m[fname] = val.FieldByName(fname).Interface()
				}
				ml = append(ml, m)
			}
		}
		return ml, nil
	}
	return nil, err
}

// UpdateDeptById updates Dept by Id and returns error if
// the record to be updated doesn't exist
func UpdateDeptById(m *Dept) (err error) {
	o := orm.NewOrm()
	v := Dept{Id: m.Id}
	// ascertain id exists in the database
	if err = o.Read(&v); err == nil {
		var num int64
		if num, err = o.Update(m); err == nil {
			fmt.Println("Number of records updated in database:", num)
		}
	}
	return
}

// DeleteDept deletes Dept by Id and returns error if
// the record to be deleted doesn't exist
func DeleteDept(id string) (err error) {
	o := orm.NewOrm()
	v := Dept{Id: id}
	// ascertain id exists in the database
	if err = o.Read(&v); err == nil {
		//清空该部门下的人员
		cleanUser(id)
		//修改子部门
		changeChildrenDept(id)
		var num int64
		if num, err = o.Delete(&Dept{Id: id}); err == nil {
			fmt.Println("Number of records deleted in database:", num)

		}
	}
	return
}

//SoftDeleteDept 软删除部门 Dept by Id and returns error if
// the record to be deleted doesn't exist
func SoftDeleteDept(id string, uname string) (err error) {
	o := orm.NewOrm()

	//	err = o.Begin() // 事务处理过程

	v := Dept{Id: id}
	if err = o.Read(&v); err == nil {
		v.Isdelete = 1
		v.Updater = uname
		v.Utime = time.Now()
		_, err = o.Update(&v)
	}

	return
}

//GetDeptByOrgId 根据单位获取部门树
//Param OrgId 单位id
//return 部门树，异常
func GetDeptByOrgId(oid string) (dlist []Dept, err error) {
	o := orm.NewOrm()
	if _, err = o.QueryTable(new(Dept)).Filter("Organization", oid).RelatedSel().Filter("isdelete", 0).Filter("status", 1).OrderBy("Seq").Limit(-1).All(&dlist); err == nil {
		return dlist, nil
	}
	return nil, err
}

//GetDeptTreeByParentIdAndOrgId 根据上级部门id与单位id构造部门树
func GetDeptTreeByParentIdAndOrgId(parentId, orgId string) (nodes []map[string]interface{}) {
	sum, err, data := GetDeptByParentAndOrgId(parentId, orgId)
	if sum != 0 && err == nil && data != nil {
		for _, val := range data {
			var node = make(map[string]interface{})
			node["id"] = val["id"]
			node["oid"] = val["org_id"]
			node["expand"] = true
			node["name"] = val["name"]
			node["pid"] = val["pid"]
			node["title"] = val["name"]
			pid, _ := val["id"].(string)
			node["children"] = GetDeptTreeByParentIdAndOrgId(pid, orgId)
			nodes = append(nodes, node)
		}
	}
	return
}

//GetDeptByParentAndOrgId 根据上级部门id与单位id查询
//Param parentId 上级部门id
//Param orgId 单位id
//return []orm.Params
func GetDeptByParentAndOrgId(parentId, orgId string) (int64, error, []orm.Params) {
	var maps []orm.Params
	var sql = "SELECT * FROM public.sys_dept ta WHERE ta.pid = ? AND ta.org_id= ? and ta.isdelete=0 and ta.status=1"
	o := orm.NewOrm()
	sum, err := o.Raw(sql, parentId, orgId).Values(&maps)
	return sum, err, maps
}

//GetDeptByPid 根据上级部门id
//Param parentId 上级部门id
//return []Dept
func GetDeptByPid(parentId string) (err error, dlist []Dept) {
	o := orm.NewOrm()
	if _, err := o.QueryTable(new(Dept)).Filter("Isdelete", 0).Filter("pid", parentId).All(&dlist); err == nil {
		return nil, dlist
	} else {
		return err, nil
	}
}

//GetDeptByName 根据部门名称获取部门
//Param name 部门名称
//Param orgId 单位id
//return Dept
func GetDeptByName(name string, oid string) (v *Dept, err error) {
	o := orm.NewOrm()
	qs := o.QueryTable(new(Dept))
	// beego.Debug(name, oid)
	var u Dept
	//beego.Debug(name)
	err = qs.Filter("Organization__Id", oid).Filter("Name", name).One(&u)
	beego.Debug(err)

	return &u, err

}

//cleanUser 清除部门下的人员
//Param deptId 部门id
func cleanUser(deptId string) {
	o := orm.NewOrm()
	o.QueryTable("sys_user_sys_depts").Filter("sys_dept_id", deptId).Update(orm.Params{"sys_dept_id": "0"})
}

//changeChildrenDept 修改部门
//Param deptId 部门id
func changeChildrenDept(id string) {
	o := orm.NewOrm()
	o.QueryTable(new(Dept)).Filter("pid", id).Update(orm.Params{"pid": "0"})
}

//DeleteUserDeptByUserId 根据用户删除用户部门关系
//Param userId 用户id
//return error
func DeleteUserDeptByUserId(userId string) error {
	o := orm.NewOrm()
	sql := "DELETE FROM public.sys_user_sys_depts ta WHERE ta.sys_user_id = ?"
	_, err := o.Raw(sql, userId).Exec()
	return err
}

//DeleteUserDeptByOrg 根据用户单位删除用户部门关系
//Param oid 单位id
//return error
func DeleteUserDeptByOrg(oid string) (err error) {
	o := orm.NewOrm()
	sql := "DELETE  FROM  sys_user_sys_depts a  where a.sys_dept_id in" +
		" ( select b.id from sys_dept b where b.Organization_id= ? )"
	_, err = o.Raw(sql, oid).Exec()
	return
}

//SetUserDept 批量设置用户部门关系
//Param []deptId 部门id
//Param users 用户id
//return error
func SetUserDept(deptId int64, users []string) error {
	//	sql := "UPDATE user_dept SET dept_id=? WHERE id in (?)"
	//	s := strings.Join(users, ",")
	//	fmt.Println("========users is :", s)
	o := orm.NewOrm()
	//	_, err := o.Raw(sql, deptId, s).Exec()
	_, err := o.QueryTable("sys_user_sys_depts").Filter("sys_user_id__in", users).Update(orm.Params{"dept_id": deptId})
	return err
}

//GetUserDeptTree 获取用户部门树, 本单位所有
//Param oid 单位id
//return error
func GetUserDeptTree(oid string) (nodes []map[string]interface{}, err error) {
	depts, err := GetDeptByOrgId(oid)
	for _, v := range depts {
		us, _ := GetUserByDept(v.Id)
		// beego.Debug(v.Id, us)
		for _, e := range us {
			var nod = make(map[string]interface{})
			nod["id"] = e.Id
			//			userprof, _ := GetUserprofById(e.Id)
			//			u, _ := GetUserById(e.UserId)
			nod["name"] = e.Abbr
			nod["pId"] = v.Id
			nod["drop"] = false
			if e.Isdelete == 0 && e.Status == 1 {
				nodes = append(nodes, nod)
			}

		}
		var node = make(map[string]interface{})
		node["id"] = v.Id
		node["name"] = v.Name
		node["pId"] = v.Pid
		node["isParent"] = true
		node["drag"] = false
		//		node["drop"] = true
		node["open"] = true
		nodes = append(nodes, node)
		// var hnode = make(map[string]interface{})
		// hnode["id"] = "isHidden" + v.Name
		// hnode["name"] = "isHidden" + v.Name
		// hnode["pId"] = v.Id
		// hnode["isHidden"] = true
		// nodes = append(nodes, hnode)

	}

	return
}

//GetUserDeptTree 获取用户部门树, 只限本部门及下级部门
//Param oid 单位id
//return error
func GetUserDeptTreeByDeptId(orgId, deptId string) (nodes []map[string]interface{}, err error) {
	depts, err := GetDeptByOrgId(orgId)
	if len(depts) > 0 {
		for _, v := range depts {
			if v.Id == deptId {
				leaf := make(map[string]interface{})
				leaf["id"] = v.Id
				leaf["title"] = v.Name
				leaf["expand"] = true
				GetDeptTree(v, depts, leaf)
				nodes = append(nodes, leaf)
			}
		}
	}
	return
}

func GetDeptTree(dept Dept, depts []Dept, node map[string]interface{}) {
	leafs := make([]map[string]interface{}, 0)
	for _, v := range depts {
		if v.Pid == dept.Id || v.ParentCode == dept.DeptCode {
			leaf := make(map[string]interface{})
			leaf["id"] = v.Id
			leaf["title"] = v.Name
			leaf["expand"] = false
			GetDeptTree(v, depts, leaf)
			leafs = append(leafs, leaf)
		}
	}
	if len(leafs) > 0 {
		node["children"] = leafs
	}
}

func GetFenjuDeptTree(orgId, deptId string) (nodes []map[string]interface{}, err error) {
	depts, err := GetDeptByOrgId(orgId)
	if len(depts) > 0 {
		for _, v := range depts {
			if v.Id == deptId {
				leaf := make(map[string]interface{})
				leaf["id"] = v.Id
				leaf["title"] = v.Name
				leaf["expand"] = true
				GetDeptTree(v, depts, leaf)
				nodes = append(nodes, leaf)
			}
		}
	}
	return
}

//AddUserDept 分配部门用户
func AddUserDept(deptid, userid string) (int64, error) {
	o := orm.NewOrm()
	dept := Dept{Id: deptid}
	user := User{Id: userid}
	m2m := o.QueryM2M(&user, "Dept")
	num, err := m2m.Add(&dept)
	return num, err
}

//GetChildrenDept 递归获取全部下级部门id
//Param 部门id ,pids *[]int64
//return pids *[]int64
func GetChildrenDept(id string, ids *[]string) {
	o := orm.NewOrm()
	var dept []Dept
	qs := o.QueryTable(new(Dept)).Filter("pid", id).Filter("Isdelete", 0).Filter("status", 1)
	count, _ := qs.Limit(-1).All(&dept)
	if count > 0 {
		for _, v := range dept {
			*ids = append(*ids, v.Id)
			GetChildrenDept(v.Id, ids)
		}
	}

}

//GetDeptChildrenStr 获取全部下级部门的id
//Param 部门id
//return str
func GetDeptChildrenStr(id string) *[]string {
	cid := "GetDeptChildrenStr.id." + id
	var ids []string
	// ids := new([]string)
	err := cache.GetCache(cid, &ids)
	if err != nil {
		GetChildrenDept(id, &ids)
		ids = append(ids, id)
		cacheExpire, _ := beego.AppConfig.Int("cache_expire")
		cache.SetCache(cid, ids, cacheExpire)
	}

	return &ids
}

//GetParentDept 获取全部上级部门的id
func GetParentDept(id string, ids *[]string) {
	o := orm.NewOrm()
	var dept Dept
	qs := o.QueryTable(new(Dept)).Filter("id", id).Filter("Isdelete", 0).Filter("status", 1)
	err := qs.One(&dept)
	if err == nil {
		*ids = append(*ids, dept.Id)
		GetChildrenDept(dept.Pid, ids)
	}

}

//GetDeptSql 获取全部下级部门的过滤sql
//Param 部门id
//return str
func GetDeptSql(id string) (sql string) {
	eds := GetDeptChildrenStr(id)
	sql = fmt.Sprintf(" and dept.id in %v", eds)
	return
}

//GetTopDept 获取本部部门
func GetTopDept(uid string) string {
	o := orm.NewOrm()
	user, _ := GetUserById(uid)
	var dept Dept
	qs := o.QueryTable(new(Dept)).Filter("Organization__Id", user.Organization.Id).Filter("Name", user.Organization.Abbr)
	qs.One(&dept)
	return dept.Id
}

func GetDeptByCode(id string) (v *Dept, err error) {
	o := orm.NewOrm()
	v = &Dept{DeptCode: id}
	if err = o.Read(v); err == nil {
		o.LoadRelated(v, "Organization")
		o.LoadRelated(v, "User")
		return v, nil
	}
	return nil, err
}

// 获取分局
func GetDeptFenJu() ([]Dept, error) {
	o := orm.NewOrm()
	var depts []Dept
	//sql := `
	//SELECT * FROM sys_dept WHERE "id"='0a929702-0f88-413f-89c3-5a2d984b6a6f' or "id" IN (
	//SELECT "id" FROM sys_dept
	//WHERE
	//parent_code='620100000000' AND name like '%分局%'
	//)
	//`
	// sql := `
	// SELECT * FROM sys_dept WHERE "id"='0a929702-0f88-413f-89c3-5a2d984b6a6f' or "id" IN (
	// SELECT "id" FROM sys_dept
	// WHERE
	// parent_code='620100000000' AND name like '%分局%'
	// )
	// ORDER BY seq DESC;`
	sql := `
	SELECT * FROM sys_dept WHERE  "id" IN (
	SELECT "id" FROM sys_dept 
	WHERE
	parent_code='620100000000' AND name like '%分局%' AND seq > 0
	)
	ORDER BY seq DESC;
	`
	_, err := o.Raw(sql).QueryRows(&depts)
	return depts, err
}
